package jmine.tec.datadigester.pacoteimportacao.driver;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import jmine.tec.datadigester.DataDigesterMessages;
import jmine.tec.datadigester.pacoteimportacao.beans.PacoteImportacaoBean;
import jmine.tec.utils.io.ReversibleOutputStream;

import org.apache.commons.io.IOUtils;

import bancosys.tec.datadigester.DataDigesterException;
import bancosys.tec.datadigester.DigesterDriver;
import bancosys.tec.datadigester.DigesterFile;

/**
 * Digester de um pacote de importacao.
 * <P>
 * Recebe um arquivo .ZIP contendo diversos outros arquivos dentro, que devem ser processados pelo DataDigester.
 * <P>
 * O Driver/Processor consegue "descobrir" em qual ordem os arquivos devem ser executados e qual o codigo de cada arquivo que deve ser
 * processado atravez do arquivo descritor 'importar_arquivos.txt' que deve estar na RAIZ do arquivo ZIP.
 * <P>
 * A lista de arquivos/codigos deve ser descrita da seguinte forma dentro do arquivo 'importar_arquivos.txt':
 * <P>
 * nome_do_arquivo|codigo_do_arquivo
 * <P>
 * Exemplo:
 * <P>
 * Cotacoes/RV/Maio/bdi2605.zip|COTACAO-PAPEL-RV-BDIN
 * 
 * @author Rafael Volpato
 */
public class PacoteImportacaoDriver implements DigesterDriver<PacoteImportacaoBean> {

    public static final String TOKEN_COMENTARIO = "#";

    public static final String TOKEN_SEPARADOR = "|";

    /**
     * Prefixo de aruivos que podem ser processados em paralelo.
     */
    public static final String ASYNC_PREFIX = "async:";

    public static final String ARQUIVO_LISTA_IMPORTACAO = "importar_arquivos.txt";

    /**
     * Transforma um arquivo ZIP que possui diversos arquivos que devem ser processados pelo DataDigester e um arquivo descritor em um
     * {@link PacoteImportacaoBean}.
     * 
     * @param file o conteudo do arquivo enviado pelo DataDigester
     * @param driverProperties propriedades para parse do arquivo.
     * @return uma instancia de {@link PacoteImportacaoBean} que representa o arquivo passado.
     */
    public PacoteImportacaoBean parse(DigesterFile file, Map<String, String> driverProperties) {
        PacoteImportacaoBean bean = new PacoteImportacaoBean();
        Map<String, ReversibleOutputStream> map = new HashMap<String, ReversibleOutputStream>();
        String[] arquivosImportar = null;
        ZipInputStream zip = null;
        try {
            zip = new ZipInputStream(file.getInputStream());
            ZipEntry entry;
            while ((entry = zip.getNextEntry()) != null) {
                if (ARQUIVO_LISTA_IMPORTACAO.equalsIgnoreCase(entry.getName())) {
                    arquivosImportar = IOUtils.toString(zip, "UTF-8").split("\r?\n");
                } else {
                    ReversibleOutputStream data = null;
                    try {
                        data = new ReversibleOutputStream();
                        IOUtils.copy(zip, data);
                        map.put(entry.getName(), data);
                    } finally {
                        IOUtils.closeQuietly(data);
                    }
                }
            }
        } catch (IOException e) {
            throw new DataDigesterException(DataDigesterMessages.PACOTE_ERRO_INESPERADO.create(), e);
        } finally {
            IOUtils.closeQuietly(zip);
        }
        if (arquivosImportar == null) {
            throw new DataDigesterException(DataDigesterMessages.PACOTE_ERRO_LISTA_ARQUIVOS_NAO_ENCONTRADA.create());
        }
        if (arquivosImportar.length == 0) {
            throw new DataDigesterException(DataDigesterMessages.PACOTE_ERRO_LISTA_ARQUIVOS_VAZIA.create());
        }
        for (String arquivoCodigo : arquivosImportar) {
            if ((arquivoCodigo == null) || (arquivoCodigo.trim().startsWith(TOKEN_COMENTARIO)) || (arquivoCodigo.trim().equals(""))) {
                continue;
            }
            boolean async = false;
            if (arquivoCodigo.startsWith(ASYNC_PREFIX)) {
                async = true;
                arquivoCodigo = arquivoCodigo.substring(ASYNC_PREFIX.length());
            }
            StringTokenizer st = new StringTokenizer(arquivoCodigo, TOKEN_SEPARADOR);
            if (st.countTokens() < 2) {
                throw new DataDigesterException(DataDigesterMessages.PACOTE_FORMATO_INESPERADO.create(arquivoCodigo));
            }
            String arquivo = st.nextToken();
            String codigo = st.nextToken();
            ReversibleOutputStream data = map.get(arquivo);
            if (data == null) {
                throw new DataDigesterException(DataDigesterMessages.PACOTE_ARQUIVO_NAO_ENCONTRADO.create(arquivo));
            }
            bean.addArquivo(codigo, arquivo, data, async);
        }
        return bean;
    }
}
